﻿#region Header

/*
Remote views based on linq
By

Pascal Hauser 
Dipl. Ing. in Informatik, Hochschule für Technik Rapperswil, 2006
Master Thesis, Hochschule für Technik Rapperswil, 2008-2010

and

Raphael Gfeller
Dipl. Ing. in Informatik, Hochschule für Technik Rapperswil, 2006
Master Thesis, Hochschule für Technik Rapperswil, 2008-2010

*/

#endregion

#region Usings

using System;
using System.Collections.Generic;
using Sebarf.Services.Interfaces;
using Sebarf.Utils.Interfaces;
using Sebastof.Services.Interfaces;
using Sebastof.Types;
using Utils;

#endregion

namespace Sebastof.ProcessChains.ProcessSteps {
	/// <summary>
	/// This is another processing step.
	/// Here we save away the original data of a transfered object so we can later check what changed.
	/// </summary>
	public class ChangeTrackingRegisterBase<T> : ProcessStep<T> {
		#region Public Properties

		[ServiceRequest]
		private IAppliedChangesOnObjectsCollectorService ObjectTrackerService { get; set; }

		[ServiceRequest]
		private IObjectTrackerMetadataService ObjectTrackerMetadataService { get; set; }

		[ServiceRequest]
		private IChangeHandlerService ChangeHandlerService { get; set; }

		[ServiceRequest]
		private IChangeHandlerDiagnosticsService ChangeHandlerDiagnosticsService { get; set; }

		[ServiceRequest]
		private IObjectHierarchyFlattenerService ObjectHierarchyFlattenerService { get; set; }

		#endregion

		#region Public Methods

		private List<Object> m_handledObjects = new List<object>();

		protected void HandleInterLinqApplicationObject(ISebastofApplicationObject obj, List<Object> handledObjects) {
			if (handledObjects.Contains(obj)) {
				return;
			}
			handledObjects.Add(obj);
			foreach (ChangeSet cs in ChangeHandlerDiagnosticsService.GetChangesByNonFullyLoadedObjectById(obj.Id)) {
				obj.SetValue(cs.field, cs.newvalue);
			}

			obj.RegisterSetValueObserver(ObjectTrackerService);
			ObjectTrackerMetadataService.SetChangeState(obj, EChangeState.Existing);

			foreach (var entry in obj.GetValues()) {
				if (entry.Value is ISebastofApplicationObject) {
					HandleInterLinqApplicationObject(entry.Value as ISebastofApplicationObject, handledObjects);
				}
				else {
					if (!(entry.Value is ValueType || entry.Value is String || entry.Value == null)) {
						HandleObject(entry.Value, handledObjects);
					}
				}
			}
		}

		protected void HandleObject(object obj, List<Object> handledObjects) {
			if (handledObjects.Contains(obj)) {
				return;
			}
			handledObjects.Add(obj);
			foreach (object entry in ObjectHierarchyFlattenerService.Flatten(obj)) {
				if (entry is ISebastofApplicationObject) {
					HandleInterLinqApplicationObject(entry as ISebastofApplicationObject, handledObjects);
				}
				else {
					if (obj == entry) {
						continue;
					}
					HandleObject(entry, handledObjects);
				}
			}
		}

		#endregion
	}
}